package com.ly.emp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.ly.common.core.bean.R;
import com.ly.emp.bean.dto.HubTeamResultBO;
import com.ly.emp.entity.HubTeamCaseOrg;
import com.ly.emp.entity.HubTeamResult;
import com.ly.emp.service.HubZsmsServiceIF;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 实现类-折算模式-不折算
 * M00001: 不折算   M00002：插值法  M00003：平均分标杆   M00004：最高分标杆法
 *
 * @author luoyun
 * @Date 2023/7/6 19:33
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class HubZsms001ServiceImpl implements HubZsmsServiceIF {

    @Override
    public R getTeamResultScore(List<HubTeamResultBO> bos, List<HubTeamResult> resultList, HubTeamCaseOrg hubTeamCaseOrg, BigDecimal kValue) {
        // String caseCode = hubTeamCaseOrg.getCaseCode();
        String saveCode = hubTeamCaseOrg.getSaveCode();
        String modeCode = hubTeamCaseOrg.getModeCode();
        Integer scale = hubTeamCaseOrg.getDecimalPlaces();
        // 保留小数处理
        Integer finalScale = scale == null ? 2 : scale;
        Object weight = hubTeamCaseOrg.getWeight();
        // 如果未做考核数据，则全部设为0
        if (CollUtil.isEmpty(bos)) {
            resultList.stream().forEach(result -> {
                // 设置折算分 、原始分
                ReflectUtil.setFieldValue(result, saveCode, new BigDecimal("0").divide(new BigDecimal("1"), finalScale, RoundingMode.HALF_UP));
                ReflectUtil.setFieldValue(result, saveCode + "Original", new Double("0"));
            });
            return R.ok();
        }
        // 汇总结果:每个人的总分
        Map<String, List<HubTeamResultBO>> empMap = bos.stream().collect(Collectors.groupingBy(HubTeamResultBO::getPsnNum));
        // 初始化每个人的分数
        Map<String, BigDecimal> summaryMap = new HashMap<>();
        resultList.stream().forEach(result -> {
            summaryMap.put(result.getPsnNum(), new BigDecimal("0"));
        });
        final BigDecimal[] sumScore = {new BigDecimal("0")};
        empMap.forEach((k, v) -> {
            // 修改上面需要考核的人员的分数，不包含k则表示，该人员录入了分数但是不考核
            if (summaryMap.containsKey(k)) {
                BigDecimal reduce = new BigDecimal("0");
                if (CollUtil.isNotEmpty(v)) {
                    reduce = v.stream().map(t -> t.getFinalScore() != null ? t.getFinalScore() : new BigDecimal("0")).reduce(BigDecimal.ZERO, BigDecimal::add);
                }
                sumScore[0] = sumScore[0].add(reduce);
                summaryMap.put(k, reduce);
            }
        });
        List<BigDecimal> sortList = new ArrayList<>();
        // 汇总分数的最大值、最小值
        AtomicReference<BigDecimal> maxScore = new AtomicReference<>(new BigDecimal("0"));
        AtomicReference<BigDecimal> minScore = new AtomicReference<>(new BigDecimal("0"));
        summaryMap.forEach((k, v) -> sortList.add(v));
        // 排序找到最大值最小值
        Collections.sort(sortList);
        maxScore.set(sortList.get(sortList.size() - 1));
        minScore.set(sortList.get(0));
        log.info("最高分：{}", maxScore.get());
        log.info("最低分：{}", minScore.get());
        // 汇总当前模块的
        resultList.stream().forEach(result -> {
            String psnNum = result.getPsnNum();
            // 个人积分、原始积分
            BigDecimal originalScore = summaryMap.get(psnNum) == null ? new BigDecimal("0") : summaryMap.get(psnNum);
            BigDecimal finalScore = new BigDecimal("0");
            // 积分公式计算
            if (StrUtil.isBlank(modeCode) || "M00001".equals(modeCode)) {
                // 不积分
                finalScore = originalScore;
            } else if ("M00002".equals(modeCode)) {
                // 插值法:  [k+（1-k）(本人积分-最低分)/(最高-最低)] * 100
                BigDecimal baseScore = new BigDecimal("100");
                if (maxScore.get().compareTo(minScore.get()) == 0) {
                    log.error("最高分与最低分相同，出错,全部以最高分计算");
                    finalScore = baseScore;
                } else {
                    finalScore = (originalScore.subtract(minScore.get()))
                            .multiply(new BigDecimal("1").subtract(kValue))
                            .divide(maxScore.get().subtract(minScore.get()), 6, RoundingMode.HALF_UP)
                            .add(kValue);
                    finalScore = baseScore.multiply(finalScore);
                }
            } else if ("M00003".equals(modeCode)) {
                // 平均分标杆: 个人积分/标杆值 *100      标杆值：平均分
                BigDecimal sumScoreBdl = sumScore[0];
                if (new BigDecimal("0").compareTo(sumScoreBdl) == 0) {
                    finalScore = new BigDecimal("0");
                } else {
                    // 标杆值：平均分
                    BigDecimal avgScoreBdl = sumScoreBdl.divide(BigDecimal.valueOf(resultList.size()), 6, RoundingMode.HALF_UP);
                    finalScore = originalScore.multiply(new BigDecimal("100")).divide(avgScoreBdl, finalScale, RoundingMode.HALF_UP);
                }
            } else if ("M00004".equals(modeCode)) {
                // 最高分标杆法: 个人积分/标杆值 *100     标杆值：最高分
                // 标杆值：最高分
                BigDecimal maxScoreBdl = maxScore.get();
                if (new BigDecimal("0").compareTo(maxScoreBdl) == 0) {
                    finalScore = new BigDecimal("0");
                } else {
                    finalScore = originalScore.multiply(new BigDecimal("100")).divide(maxScoreBdl, finalScale, RoundingMode.HALF_UP);
                }
            } else {
                log.info("找不到公式：{}", modeCode);
                finalScore = new BigDecimal("-1000");
            }
            // 统一保留小数
            finalScore = finalScore.divide(new BigDecimal("1"), finalScale, RoundingMode.HALF_UP);
            this.setResultScore(result, saveCode, finalScore, originalScore, weight);
        });
        return R.ok();
    }

    /**
     * 设置对应分数和模块
     *
     * @param result
     * @param saveCode
     * @param finalScore
     * @param originalScore
     */
    private void setResultScore(HubTeamResult result, String saveCode, Object finalScore, Object originalScore, Object weight) {
        // 设置折算分 、原始分
        if (StrUtil.isNotBlank(saveCode)) {
            ReflectUtil.setFieldValue(result, saveCode, finalScore != null ? String.valueOf(finalScore) : "0");
            ReflectUtil.setFieldValue(result, saveCode + "Original", originalScore != null ? String.valueOf(originalScore) : "0");
            ReflectUtil.setFieldValue(result, saveCode + "Weight", weight != null ? String.valueOf(weight) : "100");
        }
    }
}
